/*
 * Copyright (c) 2019.  鼎捷软件股份有限公司.All rights reserved.
 */

package com.digiwin.dap.middleware.service.impl;

import com.digiwin.dap.middleware.entity.AssociationEntity;
import com.digiwin.dap.middleware.entity.RelationAssociationEntity;
import com.digiwin.dap.middleware.service.AssociationEntityService;
import com.digiwin.dap.middleware.service.CascadeDeleteEntityService;
import com.digiwin.dap.middleware.service.RelationAssociationEntityService;
import com.digiwin.dap.middleware.exception.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;

/**
 * 级联删除服务
 */
@Service
public class CascadeDeleteEntityServiceImpl implements CascadeDeleteEntityService {

    @Autowired
    AssociationEntityService associationEntityService;

    @Autowired
    RelationAssociationEntityService relationAssociationEntityService;

    /**
     * 注入的是实体管理器,执行持久化操作
     */
    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 根据表名和SID 删除与所有关联中的关联数据
     *
     * @param name 表名
     * @param sids sid
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(String name, List<Long> sids) {
        //获取关联当前表的所有其他关联表
        List<AssociationEntity> associationEntities = associationEntityService.getAssociationEntities(name);

        for (AssociationEntity as : associationEntities) {
            //根据当前表的sid来获取依赖当前表的关联表中的所有主键
            List<Long> sidList = this.getSidByTableNameAndField(as.getTableName(), as.getFieldName(), sids);
            if (sidList.size() > 0) {
                //如果是级联删除，继续删除
                if (as.isCascadeDelete()) {
                    this.delete(as.getTableName(), sidList);
                    this.deleteByTableNameAndField(as.getTableName(), as.getFieldName(), sids);
                } else {
                    //如果不能级联删除，则需要抛出异常
                    throw new BusinessException(String.format("不能删除表%s,因为表%s引用了主键：%s", name, as.getTableName(), sids));
                }
            }
        }
    }

    /**
     * 根據表名和masteSid, slaveSid 刪除必須有此關連才能有其他關連的數據
     *
     * @param tableName 表名
     * @param masterSid
     * @param slaveSid
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteRelation(String tableName, Long masterSid, Long slaveSid) {
        List<RelationAssociationEntity> associationEntities = relationAssociationEntityService.getAssociationEntities(tableName);

        associationEntities.forEach((entity) -> {
            if (entity.isCheckSelf()) {
                deleteRelationByEntityAndCheckSelf(entity, masterSid, slaveSid);
            } else {
                deleteRelationByEntity(entity, masterSid, slaveSid);
            }
        });
    }

    /**
     * 根据某个字段删除表中数据
     *
     * @param tableName 表名
     * @param fieldName 字段名
     * @param sids      字段值列表
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteByTableNameAndField(String tableName, String fieldName, List sids) {
        if (StringUtils.isEmpty(fieldName)) {
            return;
        }
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("(");
        for (int i = 0; i < sids.size(); i++) {
            if (i != sids.size() - 1) {
                stringBuffer.append(sids.get(i) + ",");
            } else {
                stringBuffer.append(sids.get(i));
            }
        }
        stringBuffer.append(")");
        String sql = "DELETE FROM " + "`" + tableName + "`" + " WHERE " + fieldName + " IN " + stringBuffer.toString();
        entityManager.createNativeQuery(sql).executeUpdate();
    }

    /**
     * delete from tableName where masterField = masteSid and slaveField in (select sid from slaveName where checkFiled = slaveSid)
     *
     * @param entity
     * @param masterSid
     * @param slaveSid
     */
    private void deleteRelationByEntity(RelationAssociationEntity entity, Long masterSid, Long slaveSid) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("delete from `" + entity.getTableName() + "` ");
        stringBuffer.append("where `" + entity.getMasterField() + "`= " + masterSid);
        stringBuffer.append(" and `" + entity.getSlaveField() + "` in ");
        stringBuffer.append("(select `sid` from `" + entity.getSlaveTable() + "` ");
        stringBuffer.append("WHERE `" + entity.getCheckField() + "`= " + slaveSid + ")");
        System.out.println(stringBuffer.toString());
        entityManager.createNativeQuery(stringBuffer.toString()).executeUpdate();
    }

    /**
     * delete from tableName where masterField = masterSid and checkField = slaveSid
     *
     * @param entity
     * @param masterSid
     * @param slaveSid
     */
    private void deleteRelationByEntityAndCheckSelf(RelationAssociationEntity entity, Long masterSid, Long slaveSid) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("delete from `" + entity.getTableName() + "` ");
        stringBuffer.append("where `" + entity.getMasterField() + "`= " + masterSid);
        stringBuffer.append(" and `" + entity.getCheckField() + "`= " + slaveSid);
        System.out.println(stringBuffer.toString());
        entityManager.createNativeQuery(stringBuffer.toString()).executeUpdate();
    }

    /**
     * 根据表名、字段名、字段值获取Sid列表
     *
     * @param tableName 表名
     * @param fieldName 字段名
     * @param sids      字段值列表
     * @return Sid 列表
     */
    private List<Long> getSidByTableNameAndField(String tableName, String fieldName, List sids) {
        if (StringUtils.isEmpty(fieldName)) {
            return null;
        }
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("(");
        for (int i = 0; i < sids.size(); i++) {
            if (i != sids.size() - 1) {
                stringBuffer.append(sids.get(i) + ",");
            } else {
                stringBuffer.append(sids.get(i));
            }
        }
        stringBuffer.append(")");
        String sql = "SELECT SID FROM " + "`" + tableName + "`" + " WHERE " + fieldName + " IN " + stringBuffer.toString();
        List result = entityManager.createNativeQuery(sql).getResultList();
        List<Long> list = new ArrayList<>();
        list.addAll(result);
        return list;
    }
}
